#include "state_intro.h"
#include "state_stack.h"
#include "refc_ptr.h"
#include "window_win32.h"
#include "renderer.h"
#include "timer.h"
#include "jobs.h"

#include <sstream>
#include <windows.h>
#include <gl/gl.h>

#define MAX_TIME_FRAMES 4000

using namespace krryn::system;
using namespace krryn::usr;
using namespace krryn::core;

state_intro _state_intro;

class test_job : public job{
public:
	test_job(renderer *a_Renderer, timer &a_Timer) 
		: m_Renderer(a_Renderer), m_Timer(a_Timer) {}

	void execute(){
		float l_Start = m_Timer.elapsed_in_seconds();
		m_Renderer->begin();
		m_Renderer->draw();
		m_Renderer->end();
		m_Seconds += (m_Timer.elapsed_in_seconds() - l_Start);
	}

	void done() {}

	static float m_Seconds;
private:
	timer &m_Timer;
	renderer *m_Renderer;
};

float test_job::m_Seconds = 0;

// make the main thread wait until we're done rendering
class flush_job : public wait_job{
public:
	flush_job(renderer *a_Renderer, event &a_Event, timer &a_Timer)
		: wait_job(a_Event), m_Renderer(a_Renderer), m_Timer(a_Timer) {}

	void execute(){
		float l_Start = m_Timer.elapsed_in_seconds();
		m_Renderer->flush();
		m_Seconds += (m_Timer.elapsed_in_seconds() - l_Start);
	}

	static float m_Seconds;
private:
	timer &m_Timer;
	renderer *m_Renderer;
};

float flush_job::m_Seconds = 0;

window_win32 g_Window("Test", 400, 400);

state_intro::~state_intro(){
	delete m_Manager;
	m_Manager = 0;

	delete m_Renderer;
	m_Renderer = 0;
}

void state_intro::init(){
	m_Manager = new job_manager(2);
	m_Renderer = g_Window.create_renderer("opengl", *m_Manager);
	m_Frames = 0;
}

void state_intro::activate(){}

void state_intro::deactivate(){
	std::stringstream ss;
	ss << "Total: " << (m_Timer.elapsed_in_seconds()) << std::endl;
	ss << "Flush: " << flush_job::m_Seconds << " (s)" << std::endl;
	ss << "Rendering: " << test_job::m_Seconds << " (s)" << std::endl;

	::MessageBox(0, ss.str().c_str(), "Test", MB_OK);
}

void state_intro::tick(){
	m_Frames++;

	if(m_Frames > MAX_TIME_FRAMES)
		m_States.pop();

	g_Window.update();

	core::job_group l_RenderJobs("render-jobs");

	for(int i = 0; i < 20; i++){
		l_RenderJobs.add(new test_job(m_Renderer, m_Timer));
	}

	// this needs refactoring, adding one job as a dependency is 
	// conceptually simple, so the API should accomodate that.

	core::job_group l_RenderFlush("render-flush");
	l_RenderFlush.add(new flush_job(m_Renderer, m_TickDone, m_Timer));
	l_RenderFlush.depends_on_all_of(&l_RenderJobs);

//	l_RenderJobs.all_completed();
//	l_RenderJobs.every_n_completed(5, 

	m_Manager->add_group(&l_RenderJobs);

	m_TickDone.wait();
}
